package com.vincent.template.service.security.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.vincent.template.commons.base.VctPair;
import com.vincent.template.domain.SysAuthPo;
import com.vincent.template.domain.SysBindAuthGroupAuthPo;
import com.vincent.template.domain.SysBindAuthGroupRolePo;
import com.vincent.template.domain.SysBindRoleAuthPo;
import com.vincent.template.domain.SysBindUserGroupRolePo;
import com.vincent.template.domain.SysBindUserGroupUserPo;
import com.vincent.template.domain.SysBindUserRolePo;
import com.vincent.template.domain.SysRolePo;
import com.vincent.template.repository.SysAuthRepository;
import com.vincent.template.repository.SysBindAuthGroupAuthRepository;
import com.vincent.template.repository.SysBindAuthGroupRoleRepository;
import com.vincent.template.repository.SysBindRoleAuthRepository;
import com.vincent.template.repository.SysBindUserGroupRoleRepository;
import com.vincent.template.repository.SysBindUserGroupUserRepository;
import com.vincent.template.repository.SysBindUserRoleRepository;
import com.vincent.template.repository.SysRoleRepository;
import com.vincent.template.service.security.UserRoleAuthService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Vincent Wang
 * @date 2021/1/18 14:23
 */
@Service
public class UserRoleAuthServiceImpl implements UserRoleAuthService {

    @Autowired
    private SysRoleRepository roleRepository;
    @Autowired
    private SysBindUserRoleRepository bindUserRoleRepository;
    @Autowired
    private SysBindUserGroupUserRepository bindUserGroupUserRepository;
    @Autowired
    private SysBindUserGroupRoleRepository bindUserGroupRoleRepository;
    @Autowired
    private SysBindRoleAuthRepository bindRoleAuthRepository;
    @Autowired
    private SysBindAuthGroupRoleRepository bindAuthGroupRoleRepository;
    @Autowired
    private SysBindAuthGroupAuthRepository bindAuthGroupAuthRepository;
    @Autowired
    private SysAuthRepository authRepository;

    @Override
    public VctPair<List<String>, List<String>> findRolesAndAuths(String userId) {
        Set<Long> roleIds = findRoleIds(userId);
        if (CollectionUtils.isEmpty(roleIds)) {
            return VctPair.of(Lists.newArrayList(), Lists.newArrayList());
        }
        List<SysRolePo> roles = roleRepository.findAllById(roleIds);
        if (CollectionUtils.isEmpty(roles)) {
            return VctPair.of(Lists.newArrayList(), Lists.newArrayList());
        }
        List<String> roleCodes = roles.stream().map(SysRolePo::getCode).collect(Collectors.toList());
        List<String> authCodes = findAuthCodes(roleIds);
        return VctPair.of(roleCodes, authCodes);
    }

    /**
     * 根据用户id查询拥有的角色id
     * @param userId
     * @return
     */
    private Set<Long> findRoleIds(String userId) {
        Set<Long> roleIds = Sets.newHashSet();
        // 用户绑定的角色
        List<SysBindUserRolePo> userRoleBindings = bindUserRoleRepository.findByUserId(userId);
        if (CollectionUtils.isNotEmpty(userRoleBindings)) {
            roleIds.addAll(userRoleBindings.stream().map(SysBindUserRolePo::getRoleId).collect(Collectors.toSet()));
        }
        // 用户绑定的用户组，以及用户组绑定的角色
        List<SysBindUserGroupUserPo> userGroupUserBindings = bindUserGroupUserRepository.findByUserId(userId);
        if (CollectionUtils.isNotEmpty(userGroupUserBindings)) {
            Set<Long> userGroupIds = userGroupUserBindings.stream()
                    .map(SysBindUserGroupUserPo::getUserGroupId).collect(Collectors.toSet());
            List<SysBindUserGroupRolePo> userGroupRoleBindings =
                    bindUserGroupRoleRepository.findByUserGroupIdIn(userGroupIds);
            if (CollectionUtils.isNotEmpty(userGroupRoleBindings)) {
                roleIds.addAll(userGroupRoleBindings.stream()
                        .map(SysBindUserGroupRolePo::getRoleId).collect(Collectors.toSet()));
            }
        }
        return roleIds;
    }

    /**
     * 根据角色id查询所有绑定的权限code
     * @param roleIds
     * @return
     */
    private List<String> findAuthCodes(Set<Long> roleIds) {
        Set<Long> authIds = Sets.newHashSet();
        // 角色绑定的权限
        List<SysBindRoleAuthPo> roleAuthBindings = bindRoleAuthRepository.findByRoleIdIn(roleIds);
        if (CollectionUtils.isNotEmpty(roleAuthBindings)) {
            authIds.addAll(roleAuthBindings.stream().map(SysBindRoleAuthPo::getAuthId).collect(Collectors.toSet()));
        }
        // 角色绑定的权限组，以及权限组下绑定的权限
        List<SysBindAuthGroupRolePo> authGroupRoleBindings = bindAuthGroupRoleRepository.findByRoleIdIn(roleIds);
        if (CollectionUtils.isNotEmpty(authGroupRoleBindings)) {
            Set<Long> authGroupIds = authGroupRoleBindings.stream()
                    .map(SysBindAuthGroupRolePo::getAuthGroupId).collect(Collectors.toSet());
            List<SysBindAuthGroupAuthPo> authGroupAuthBindings =
                    bindAuthGroupAuthRepository.findByAuthGroupIdIn(authGroupIds);
            if (CollectionUtils.isNotEmpty(authGroupAuthBindings)) {
                authIds.addAll(authGroupAuthBindings.stream()
                        .map(SysBindAuthGroupAuthPo::getAuthId).collect(Collectors.toSet()));
            }
        }
        if (CollectionUtils.isEmpty(authIds)) {
            return Lists.newArrayList();
        }
        // 根据权限id找到对应的权限Code
        List<SysAuthPo> auths = authRepository.findAllById(authIds);
        if (CollectionUtils.isEmpty(auths)) {
            return Lists.newArrayList();
        }
        return auths.stream().map(SysAuthPo::getCode).collect(Collectors.toList());
    }

}
